import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.math.BigDecimal;

/**
 * 
 * 
 * @author Nizar Oukhchi
 * 
 */
public class Tokenizer {
	private static final int EOS = -1;
	private static final int CR = '\r';
	private static final int LF = '\n';
	private BufferedReader in;
	private int data;
	private Token token;
	private Token prevToken;
	private StringBuilder sb = new StringBuilder();
	boolean isPrevious =  false;
	

	public Tokenizer(Reader in) { // done
		this.in = new BufferedReader(in);
	}

	public Token next() throws IOException //done
	{
		skipWhites();
		data = in.read();
		if (isIdStart()) {
			identificator();
			token = new Token(Token.Type.ID, sb.toString(), null);
			sb.setLength(0);
			return token;
		} else if (isNumber()) {
			number();
			token = new Token(Token.Type.NUM, null, new BigDecimal(
					sb.toString()));
			sb.setLength(0);
			return token;
		}
		switch (data) {
		case EOS:
			token = new Token(Token.Type.EOS);
			sb.setLength(0);
			return token;
		case '+':
			token = new Token(Token.Type.PLUS);
			sb.setLength(0);
			return token;
		case '-':
			token = new Token(Token.Type.MINUS);
			sb.setLength(0);
			return token;
		case '*':
			token = new Token(Token.Type.TIMES);
			sb.setLength(0);
			return token;
		case '/':
			token = new Token(Token.Type.DIV);
			sb.setLength(0);
			return token;
		case '=':
			token = new Token(Token.Type.BECOMES);
			sb.setLength(0);
			return token;
		case ';':
			token = new Token(Token.Type.SEMICOLON);
			sb.setLength(0);
			return token;
		case ')':
			token = new Token(Token.Type.CLOSEPAR);
			sb.setLength(0);
			return token;
		case '(':
			token = new Token(Token.Type.OPENPAR);
			sb.setLength(0);
			return token;
		default:
			token = new Token(Token.Type.UNKNOWN);
			sb.setLength(0);
			return token;


		}
	}

	private void skipWhites() throws IOException // TODO aggiungere lo skip dei commenti
	{

		in.mark(1);
		while (Character.isWhitespace(in.read())) {	
			in.mark(1);
			continue;
		}
		in.reset();
	}

	private void skipLineComment() throws IOException {
		do {
			in.read();
		} while (!isEoL());
	}

	private  boolean isEoL()
	{
		return data == CR || data == LF;
	}

	// // Identificator
	private boolean isIdStart() throws IOException { // done
		return Character.isLetter(data);
	}

	private void identificator() throws IOException // done
	{
		while (isIdStart()) {
			sb.append((char) data);
			in.mark(1);
			data = in.read();
		}
		in.reset();
	}

	// // number

	private boolean isNumber() // done
	{
		return Character.isDigit(data);
	}

	private void number() throws IOException // done
	{
		while (isNumber()) {
			sb.append((char) data);
			in.mark(1);
			data = in.read();
		}
		if (data == '.') {
			fractionPart();
		}
		if (data == 'E' || data == 'e') {
			exponent();
		}
		in.reset();
	}

	private void fractionPart() throws IOException { // done
		int temp1 = data;
		in.mark(1);
		data = in.read();
		if (Character.isDigit(data)) {
			sb.append((char) temp1);
			do {
				sb.append((char) data);
				in.mark(1);
				data = in.read();
			} while (Character.isDigit(data));

		}
		// in.reset();
	}

	private void exponent() throws IOException { // done
		int temp1 = data;
		int temp2 = 0;
		data = in.read();
		if (data == '+' || data == '-') {
			temp2 = data;
			data = in.read();
			if (Character.isDigit(data)) {
				sb.append((char) temp1);
				sb.append((char) temp2);
				do {
					sb.append((char) data);
					in.mark(1);
					data = in.read();
				} while (Character.isDigit(data));
			}
		} else if (Character.isDigit(data)) {
			sb.append((char) temp1);
			if (Character.isDigit(data)) {
				do {
					// sb.append((char)temp1);
					sb.append((char) data);
					in.mark(1);
					data = in.read();
				} while (Character.isDigit(data));
			}
			in.reset();
		}
	}

	public Token prev(){
		return prevToken;
	}

	/*
	 * private boolean isOperand() throws IOException { if(data == '+' ||data ==
	 * '+' ||data == '+' ||data == '+' ||data == '+' ||data == '+' ||)
	 * 
	 * } }
	 */

	/*
	 * private boolean isOp(){ if(data == '+' || data == '-' || data == '*' || )
	 * }
	 */

	// for test

	public static void main(String[] args) throws IOException {
		FileReader in = new FileReader("test.txt");
		Tokenizer t = new Tokenizer(in);
		Token to = new Token(null);
		do {
			to = t.next();
			System.out.println(to.getType() + " " + to.getNum());
		} while (to.getType() != Token.Type.EOS);
	}
}
